//
//  UIImage+MLKit.m
//  MLIM
//
//  Created by molon on 15/6/25.
//  Copyright (c) 2015年 molon. All rights reserved.
//

#import "UIImage+MLKit.h"
#import "NSString+MLKit.h"

@implementation UIImage (MLKit)


#pragma mark - common

- (UIImage *)fixOrientation {
    
    if (self.imageOrientation == UIImageOrientationUp) return self;
    
    CGAffineTransform transform = CGAffineTransformIdentity;
    
    UIImageOrientation io = self.imageOrientation;
    if (io == UIImageOrientationDown || io == UIImageOrientationDownMirrored) {
        transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
        transform = CGAffineTransformRotate(transform, M_PI);
    }else if (io == UIImageOrientationLeft || io == UIImageOrientationLeftMirrored) {
        transform = CGAffineTransformTranslate(transform, self.size.width, 0);
        transform = CGAffineTransformRotate(transform, M_PI_2);
    }else if (io == UIImageOrientationRight || io == UIImageOrientationRightMirrored) {
        transform = CGAffineTransformTranslate(transform, 0, self.size.height);
        transform = CGAffineTransformRotate(transform, -M_PI_2);
        
    }
    
    if (io == UIImageOrientationUpMirrored || io == UIImageOrientationDownMirrored) {
        transform = CGAffineTransformTranslate(transform, self.size.width, 0);
        transform = CGAffineTransformScale(transform, -1, 1);
    }else if (io == UIImageOrientationLeftMirrored || io == UIImageOrientationRightMirrored) {
        transform = CGAffineTransformTranslate(transform, self.size.height, 0);
        transform = CGAffineTransformScale(transform, -1, 1);
        
    }
    
    CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
                                             CGImageGetBitsPerComponent(self.CGImage), 0,
                                             CGImageGetColorSpace(self.CGImage),
                                             CGImageGetBitmapInfo(self.CGImage));
    CGContextConcatCTM(ctx, transform);
    
    if (io == UIImageOrientationLeft || io == UIImageOrientationLeftMirrored || io == UIImageOrientationRight || io == UIImageOrientationRightMirrored) {
        CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
    }else{
        CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
    }
    
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}


//是否有透明路径
- (BOOL)hasAlpha
{
    CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
    return (alpha == kCGImageAlphaFirst ||
            alpha == kCGImageAlphaLast ||
            alpha == kCGImageAlphaPremultipliedFirst ||
            alpha == kCGImageAlphaPremultipliedLast);
}

//没透明路径就加上
- (UIImage *)imageWithAlpha
{
    if ([self hasAlpha]) {
        return self;
    }
    
    CGFloat scale = MAX(self.scale, 1.0f);
    CGImageRef imageRef = self.CGImage;
    size_t width = CGImageGetWidth(imageRef)*scale;
    size_t height = CGImageGetHeight(imageRef)*scale;
    
    CGContextRef offscreenContext = CGBitmapContextCreate(NULL,width,height,8,0,CGImageGetColorSpace(imageRef),
                                                          kCGBitmapByteOrderDefault |kCGImageAlphaPremultipliedFirst);
    
    CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef);
    CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext);
    UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha scale:self.scale orientation:UIImageOrientationUp];
    
    CGContextRelease(offscreenContext);
    CGImageRelease(imageRefWithAlpha);
    
    return imageWithAlpha;
}

#pragma mark - corner
- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius
{
    return [self imageByRoundCornerRadius:radius corners:UIRectCornerAllCorners borderWidth:0];
}

- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius corners:(UIRectCorner)corners borderWidth:(CGFloat)borderWidth
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGContextScaleCTM(context, 1, -1);
    CGContextTranslateCTM(context, 0, -rect.size.height);
    
    CGFloat minSize = MIN(self.size.width, self.size.height);
    if (borderWidth < minSize / 2) {
        [[UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:CGSizeMake(radius, borderWidth)] addClip];
        CGContextDrawImage(context, rect, self.CGImage);
    }
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

#pragma mark - color
+ (UIImage *)imageWithPureColor:(UIColor*)color
{
    return [self imageWithPureColor:color withSize:CGSizeMake(1, 1)];
}

+ (UIImage *)imageWithPureColor:(UIColor*)color withSize:(CGSize)size
{
    CGSize imageSize = size;
    UIGraphicsBeginImageContextWithOptions(imageSize, 0, [UIScreen mainScreen].scale);
    [color set];
    UIRectFill(CGRectMake(0, 0, imageSize.width, imageSize.height));
    UIImage *pressedColorImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return pressedColorImg;
}

- (UIImage *)grayImage
{
    int width = self.size.width;
    int height = self.size.height;
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGContextRef context = CGBitmapContextCreate (nil,width,height,8,0,colorSpace,(CGBitmapInfo)kCGImageAlphaNone);
    CGColorSpaceRelease(colorSpace);
    
    if (context == NULL) {
        return nil;
    }
    
    CGContextDrawImage(context,CGRectMake(0, 0, width, height), self.CGImage);
    CGImageRef imageRef = CGBitmapContextCreateImage(context);
    UIImage *grayImage = [UIImage imageWithCGImage:imageRef];
    CFRelease(imageRef);
    CGContextRelease(context);
    
    return grayImage;
}

- (UIImage *)imageWithTintColor:(UIColor *)tintColor
{
    return [self imageWithTintColor:tintColor blendMode:kCGBlendModeDestinationIn];
}

- (UIImage *)imageWithGradientTintColor:(UIColor *)tintColor
{
    return [self imageWithTintColor:tintColor blendMode:kCGBlendModeOverlay];
}

- (UIImage *)imageWithTintColor:(UIColor *)tintColor blendMode:(CGBlendMode)blendMode
{
    //We want to keep alpha, set opaque to NO; Use 0.0f for scale to use the scale factor of the device’s main screen.
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    [tintColor setFill];
    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
    UIRectFill(bounds);
    
    //Draw the tinted image in context
    [self drawInRect:bounds blendMode:blendMode alpha:1.0f];
    
    if (blendMode != kCGBlendModeDestinationIn) {
        [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f];
    }
    
    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    if ([tintedImage respondsToSelector:@selector(imageWithRenderingMode:)]) {
        tintedImage = [tintedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    }
    
    return tintedImage;
}

#pragma mark - 水印
- (UIImage*)imageWithTextWatermark:(NSString*)text andFont:(UIFont*)font andColor:(UIColor*)color andAngle:(CGFloat)angle andPoints:(NSArray*)points
{
    //原图
    UIGraphicsBeginImageContextWithOptions(self.size, NO, [UIScreen mainScreen].scale);
    
    //原图
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
    
    //水印文字
    for (NSValue *value in points) {
        CGPoint point = [value CGPointValue];
        if (point.x>self.size.width) {
            continue;
        }
        if (point.y>self.size.height) {
            continue;
        }
        [text drawWithBasePoint:point andAngle:angle andFont:font andColor:color];
    }
    
    UIImage *newPic = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newPic;
}


#pragma mark - 压缩和裁剪
static dispatch_queue_t image_compression_concurrent_queue() {
    static dispatch_queue_t ml_image_compression_concurrent_queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        ml_image_compression_concurrent_queue = dispatch_queue_create("com.molon.ml_image_compression_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
    });
    
    return ml_image_compression_concurrent_queue;
}

- (void)dataFoCompressImageToMaxDataLength:(NSUInteger)maxDataLength maxSideLength:(CGFloat)maxSideLength withCallback:(void(^)(UIImage *originalImage,NSData *compressedData))callback
{
    //    NSAssert(maxDataLength>1*1024, ([NSString stringWithFormat:@"%s:%d->%@",__PRETTY_FUNCTION__, __LINE__,@"maxDataLength必须大于1024"]));
    
    dispatch_async(image_compression_concurrent_queue(), ^{
        UIImage *image = [self copy];
        
        if (maxSideLength>0) {
            image = [image imageByScalingToMinSideLength:maxSideLength];
        }
        
        //先找到某分辨率的最大压缩比时候有达到设置数据大小的可能
        while (UIImageJPEGRepresentation(image, 0).length>maxDataLength) {
            if (MIN(image.size.width, image.size.height)<1) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    callback(self,nil);
                });
                return; //都小于1了还压个屁啊，压好了也看不到了啊，没完没了了。
            }
            //换image,分辨率缩小一半
            image = [image imageByScalingToMinSideLength:MIN(image.size.width, image.size.height)/2];
        }
        
        //当前分辨率下最好的满足条件的压缩比
        CGFloat compression = 0.99f;
        NSData *imageData = UIImageJPEGRepresentation(image, compression);
        while (imageData.length > maxDataLength&&compression>0){
            compression -= 0.01;
            if (compression<0) {
                compression = 0;
            }
            
            imageData = UIImageJPEGRepresentation(image, compression);
            
            if (compression==0) {
                break;
            }
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            callback(self,imageData);
        });
    });
}

- (UIImage*)imageByScalingToMinSideLength:(CGFloat)minSideLength
{
    CGFloat ratio = MIN(self.size.height,self.size.width) / minSideLength;
    CGSize  sizeForAspectScale = CGSizeMake(self.size.width / ratio, self.size.height / ratio);
    return [self imageByScalingAspectFillSize:sizeForAspectScale];
}

- (UIImage*)imageByScalingToSize:(CGSize)newSize contentMode:(UIViewContentMode)contentMode
{
    if (contentMode == UIViewContentModeScaleToFill)
    {
        return [self imageByScalingToFillSize:newSize];
    }
    else if ((contentMode == UIViewContentModeScaleAspectFill) ||
             (contentMode == UIViewContentModeScaleAspectFit))
    {
        CGFloat horizontalRatio   = self.size.width  / newSize.width;
        CGFloat verticalRatio     = self.size.height / newSize.height;
        CGFloat ratio;
        
        if (contentMode == UIViewContentModeScaleAspectFill)
            ratio = MIN(horizontalRatio, verticalRatio);
        else
            ratio = MAX(horizontalRatio, verticalRatio);
        
        CGSize  sizeForAspectScale = CGSizeMake(self.size.width / ratio, self.size.height / ratio);
        
        UIImage *image = [self imageByScalingToFillSize:sizeForAspectScale];
        
        // if we're doing aspect fill, then the image still needs to be cropped
        
        if (contentMode == UIViewContentModeScaleAspectFill)
        {
            CGRect  subRect = CGRectMake(floor((sizeForAspectScale.width - newSize.width) / 2.0),
                                         floor((sizeForAspectScale.height - newSize.height) / 2.0),
                                         newSize.width,
                                         newSize.height);
            image = [image imageByCroppingToBounds:subRect];
        }
        
        return image;
    }
    
    return nil;
}

- (UIImage *)imageByCroppingToBounds:(CGRect)bounds
{
    CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
    UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    return croppedImage;
}

- (UIImage*)imageByScalingToFillSize:(CGSize)newSize
{
    UIGraphicsBeginImageContext(newSize);
    [self drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return image;
}

- (UIImage*)imageByScalingAspectFillSize:(CGSize)newSize
{
    return [self imageByScalingToSize:newSize contentMode:UIViewContentModeScaleAspectFill];
}

- (UIImage*)imageByScalingAspectFitSize:(CGSize)newSize
{
    return [self imageByScalingToSize:newSize contentMode:UIViewContentModeScaleAspectFit];
}

#pragma mark - mask
- (UIImage*)maskImageWithMask:(UIImage *)maskImage
{
    CGImageRef maskRef = maskImage.CGImage;
    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                        CGImageGetHeight(maskRef),
                                        CGImageGetBitsPerComponent(maskRef),
                                        CGImageGetBitsPerPixel(maskRef),
                                        CGImageGetBytesPerRow(maskRef),
                                        CGImageGetDataProvider(maskRef), NULL, false);
    
    CGImageRef masked = CGImageCreateWithMask([[self imageWithAlpha] CGImage], mask);
    CGImageRelease(mask);
    UIImage *maskedImage = [UIImage imageWithCGImage:masked];
    CGImageRelease(masked);
    
    return maskedImage;
}

@end
